﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Windows.Forms;
using YAPSAR.Native;
using System.ComponentModel;

namespace YAPSAR.Collector
{
    public class ProcessListener
    {
        private static ProcessListener static_instance;
        public static ProcessListener Instance
        {
            get
            {
                if (static_instance == null)
                {
                    static_instance = new ProcessListener();
                }

                return static_instance;
            }
        }

        private const int INTERVAL_START = 500;
        private const int INTERVAL_INCREASE = 25;
        private const int INTERVAL_MAX = 10000;

        public String CurrentWindowTitle
        {
            get
            {
                return this.previousWindowTitle;
            }
        }

        public event EventHandler<ProcessInfoEventArgs> ActiveProcessChanged;

        private Timer timer;
        private int previousProcessId;
        private String previousWindowTitle;

        public class ProcessInfoEventArgs : EventArgs
        {
            public int ProcessID { get; set; }
            public String Title { get; set; }
            public String FilePath { get; set; }

            public override string ToString()
            {
                return this.ProcessID + " > " + this.Title + " @ " + this.FilePath;
            }
        }

        private ProcessListener()
        {

        }

        ~ProcessListener()
        {
            this.Stop();
        }

        public void Start()
        {
            this.timer = new Timer();
            this.timer.Interval = INTERVAL_START;

            this.timer.Tick += new EventHandler(timer_Tick);
            this.timer.Start();
        }

        public void Stop()
        {
            this.timer.Stop();
            this.timer.Dispose();
        }

        private void timer_Tick(object sender, EventArgs e)
        {
            IntPtr hwnd = UnsafeMethods.GetForegroundWindow();
            int pid;
            UnsafeMethods.GetWindowThreadProcessId(hwnd, out pid);

            // The pid might be 0 if the tick happens right when we are switching between windows.
            if (pid != 0 && this.previousProcessId != pid)
            {
                this.previousProcessId = pid;
                var p = Process.GetProcessById((int)pid);

                String processFilename = null;
                try
                {
                    processFilename = p.MainModule.FileName;
                }
                catch (Win32Exception ex)
                {
                    Console.WriteLine("Could not get MainModule of pid '" + pid + "', because: " + ex.Message);
                }

                var processTitle = p.MainWindowTitle;

                if (this.ActiveProcessChanged != null)
                {
                    var info = new ProcessInfoEventArgs()
                    {
                        ProcessID = pid,
                        FilePath = processFilename,
                        Title = processTitle
                    };

                    this.ActiveProcessChanged(this, info);
                }

                // Reset the interval, since we seem to be going into change-windows mode.
                this.timer.Interval = INTERVAL_START;
            }
            else
            {
                if (this.timer.Interval < INTERVAL_MAX)
                {
                    // Keep increasing the timer interval to a max of INTERVAL_MAX milliseconds.
                    // This way we won't keep spamming with checks, since we seem to be stuck at the same window anyway.
                    this.timer.Interval += INTERVAL_INCREASE;
                }
            }
        }
    }
}
